package com.crx.springbootinit.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.crx.springbootinit.common.WebSocketServer;
import com.crx.springbootinit.exception.ThrowUtils;
import com.crx.springbootinit.model.dto.follow.FollowUserPageDTO;
import com.crx.springbootinit.model.dto.follow.FollowOperationDTO;
import com.crx.springbootinit.model.dto.follow.FollowPageDTO;
import com.crx.springbootinit.model.dto.page.PageQuery;
import com.crx.springbootinit.model.dto.page.PageVO;
import com.crx.springbootinit.model.entity.Follow;
import com.crx.springbootinit.mapper.FollowMapper;
import com.crx.springbootinit.model.entity.Post;
import com.crx.springbootinit.model.vo.follow.FollowMeNoticeVO;
import com.crx.springbootinit.model.vo.follow.FollowPageVo;
import com.crx.springbootinit.model.vo.follow.FansVO;
import com.crx.springbootinit.model.vo.follow.FollowVO;
import com.crx.springbootinit.service.IFollowService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.crx.springbootinit.service.IPostService;
import com.crx.springbootinit.service.IUserService;
import com.crx.springbootinit.utils.AuthUtils;
import com.crx.springbootinit.utils.ThreadLocalUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.List;

import static com.crx.springbootinit.common.ErrorCode.*;

/**
 * <p>
 * 关注表 服务实现类
 * </p>
 *
 * @author author
 * @since 2024-10-21
 */
@Service
public class FollowServiceImpl extends ServiceImpl<FollowMapper, Follow> implements IFollowService {
    @Autowired
    private  RedisTemplate redisTemplate;
    @Autowired
    private  IPostService postService;

    private  IUserService userService;

    public FollowServiceImpl(@Lazy IUserService userService){
        this.userService=userService;
    }


    @Override
    public void followOperation(FollowOperationDTO followOperationDTO) {
        //1.获取校验请求参数
        Long userId = ThreadLocalUtil.get("userId");
        Long followedId = followOperationDTO.getFollowedId();
        Boolean isFollow = followOperationDTO.getIsFollow();
        if(userId==null){
            ThrowUtils.throwIf(true,NOT_LOGIN_ERROR,"未登录，用户id为空");
        }
        //2.判断是关注还是取消关注，如果isFollow 为true，则关注，为false，则取消关注
        //3.关注，判断关注表是否有记录,没有则添加一条数据，取消关注，判断关注表表是否记录，有则删除数据
        if(isFollow){
            if(isFollow(userId,followedId)){
                ThrowUtils.throwIf(true,OPERATION_ERROR,"关注失败，已关注过该用户");
            }
            Follow followPO = BeanUtil.copyProperties(followOperationDTO, Follow.class);
            followPO.setFollowId(userId);
            if(save(followPO)){
                try {
                    String nickname = userService.getById(followedId).getNickname();
                    WebSocketServer.sendNotification(followedId,nickname+"关注了你");
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
        }else{
           if(!isFollow(userId,followedId)){
               ThrowUtils.throwIf(true,OPERATION_ERROR,"取消关注失败，未关注过该用户");
           }
            LambdaQueryWrapper<Follow> wrapper = new LambdaQueryWrapper<Follow>()
                    .eq(Follow::getFollowId,userId)
                    .eq(Follow::getFollowedId,followedId);
            remove(wrapper);
        }

    }

    @Override
    public PageVO<FollowMeNoticeVO> getFollowMeNoticeList(PageQuery pageQuery) {
        Long userId = ThreadLocalUtil.get("userId");
        Page<FollowMeNoticeVO> page = new Page<>(pageQuery.getPageNo(), pageQuery.getPageSize());
        IPage<FollowMeNoticeVO> iPage=baseMapper.getFollowMeNoticeList(page,userId);
        PageVO<FollowMeNoticeVO> pageVO=new PageVO<>();
        pageVO.setList(iPage.getRecords());
        pageVO.setTotal(iPage.getTotal());
        pageVO.setPages(iPage.getPages());
        return pageVO ;
    }

    @Override
    public Long getFollowCount(String token) {
        Long userId= AuthUtils.getUserId(redisTemplate,token);
        Long count = lambdaQuery().eq(Follow::getFollowId, userId).count();
        return count;
    }

    @Override
    public Long getFollowCountByUserId(Long userId) {
        Long count = lambdaQuery().eq(Follow::getFollowId, userId).count();
        return count;
    }

    @Override
    public Long getFansCount(String token) {
        Long userId= AuthUtils.getUserId(redisTemplate,token);
        Long count = lambdaQuery().eq(Follow::getFollowedId, userId).count();
        return count;
    }

    @Override
    public Long getFansCountByUserId(Long userId) {
        Long count = lambdaQuery().eq(Follow::getFollowedId, userId).count();
        return count;
    }
    @Override
    public PageVO<FollowVO> getFollowPage(PageQuery pageQuery) {
        Long userId = ThreadLocalUtil.get("userId");
        Page<FollowVO> page = new Page<>(pageQuery.getPageNo(), pageQuery.getPageSize());
        IPage<FollowVO> iPage=baseMapper.getFollowPage(page ,userId);
        iPage.getRecords().forEach(item->{
            item.setPostCount(postService.lambdaQuery().eq(Post::getUserId, item.getFollowedId()).count());
            item.setFansCount(lambdaQuery().eq(Follow::getFollowedId,item.getFollowedId()).count());
            item.setIsFollow(lambdaQuery().eq(Follow::getFollowId,userId).eq(Follow::getFollowedId,item.getFollowedId()).exists());
        });
        PageVO<FollowVO> pageVO=new PageVO<>();
        pageVO.setList(iPage.getRecords());
        pageVO.setTotal(iPage.getTotal());
        pageVO.setPages(iPage.getPages());
        return pageVO;
    }

    @Override
    public PageVO<FansVO> getFansPage(PageQuery pageQuery) {
        Long userId = ThreadLocalUtil.get("userId");
        Page<FansVO> page = new Page<>(pageQuery.getPageNo(), pageQuery.getPageSize());
        IPage<FansVO> iPage=baseMapper.getFansPage(page,userId);
        iPage.getRecords().forEach(item->{
            item.setPostCount(postService.lambdaQuery().eq(Post::getUserId, item.getFollowId()).count());
            item.setFansCount(lambdaQuery().eq(Follow::getFollowedId,item.getFollowId()).count());
        });
        PageVO<FansVO> pageVO=new PageVO<>();
        pageVO.setList(iPage.getRecords());
        pageVO.setTotal(iPage.getTotal());
        pageVO.setPages(iPage.getPages());
        return pageVO;
    }

    @Override
    public PageVO<FollowPageVo> queryFollowPage(FollowPageDTO followPageDTO) {
        Page<FollowPageVo> page = new Page<>(followPageDTO.getPageNo(), followPageDTO.getPageSize());
        IPage<FollowPageVo> followPage=baseMapper.queryFollowPage(page,followPageDTO);
        PageVO<FollowPageVo> followPageVoPageVO = new PageVO<>();
        followPageVoPageVO.setList(followPage.getRecords());
        followPageVoPageVO.setPages(followPage.getPages());
        followPageVoPageVO.setTotal(followPage.getTotal());
        return followPageVoPageVO;
    }
    @Override
    public Boolean isFollow(Long followId, Long followedId){
        return lambdaQuery().eq(Follow::getFollowId,followId).eq(Follow::getFollowedId,followedId).exists();
    }
}
